
/**
 * @author stefan.liebenberg@lfpug.com (Stefan)
 * @fileoverview Provides a Base List Class that other list can inherit from.
 */
goog.provide('lfpug.ui.component.list.BaseList');
goog.require('lfpug.events.ArrayCollectionEvent.EventType');
goog.require('lfpug.ui.Component');



/**
 * @constructor
 * @extends {lfpug.ui.Component}
 *
 * @param {lfpug.ui.type.Model} model
 *        The component model.
 *
 * @param {lfpug.ui.Renderer=} opt_renderer
 *        Optional renderer.
 */
lfpug.ui.component.list.BaseList = function(model, opt_renderer) {
  goog.base(this, model, opt_renderer);
};
goog.inherits(
    lfpug.ui.component.list.BaseList,
    lfpug.ui.Component
);


/**
 * @return {Object.<lfpug.ui.component.list.BaseList.EventMapIndex,
 * lfpug.events.ArrayCollectionEvent.EventType>}
  *        returns a map of events to other events.
 */
lfpug.ui.component.list.BaseList.prototype.getModelEventsMap =
    function() {
  var map = {};
  var events = lfpug.events.ArrayCollectionEvent.EventType;
  var map_index = lfpug.ui.component.list.BaseList.EventMapIndex;
  map[map_index.ADD] = events.ADD;
  map[map_index.REMOVE] = events.REMOVE;
  map[map_index.CHANGE] = events.CHANGE;
  map[map_index.MOVE] = events.MOVE;
  return map;
};


/**
 * @protected
 */
lfpug.ui.component.list.BaseList.prototype.setupBindingsInternal =
    function() {
  var model = this.getModel();
  var events = this.getModelEventsMap();

  goog.events.listen(
      model,
      events[lfpug.ui.component.list.BaseList.EventMapIndex.ADD],
      this.addEventInternal,
      undefined,
      this
  );

  goog.events.listen(
      model,
      events[lfpug.ui.component.list.BaseList.EventMapIndex.REMOVE],
      this.removeEventInternal,
      undefined,
      this
  );

  goog.events.listen(
      model,
      events[lfpug.ui.component.list.BaseList.EventMapIndex.CHANGE],
      this.changeEventInternal,
      undefined,
      this
  );

  goog.events.listen(
      model,
      events[lfpug.ui.component.list.BaseList.EventMapIndex.MOVE],
      this.moveEventInternal,
      undefined,
      this
  );
};


/**
 * @enum {string|number}
 */
lfpug.ui.component.list.BaseList.EventMapIndex = {
  ADD: 0,
  REMOVE: 1,
  CHANGE: 2,
  MOVE: 3
};


/**
 * @protected
 */
lfpug.ui.component.list.BaseList.prototype.teardownBindingsInternal =
    function() {
  var model = this.getModel();
  var events = this.getModelEventsMap();

  goog.events.unlisten(
      model,
      events[lfpug.ui.component.list.BaseList.EventMapIndex.ADD],
      this.addEventInternal,
      undefined,
      this
  );

  goog.events.unlisten(
      model,
      events[lfpug.ui.component.list.BaseList.EventMapIndex.REMOVE],
      this.removeEventInternal,
      undefined,
      this
  );

  goog.events.unlisten(
      model,
      events[lfpug.ui.component.list.BaseList.EventMapIndex.CHANGE],
      this.changeEventInternal,
      undefined,
      this
  );

  goog.events.unlisten(
      model,
      events[lfpug.ui.component.list.BaseList.EventMapIndex.MOVE],
      this.moveEventInternal,
      undefined,
      this
  );
};


/**
 * @protected
 *
 * @param {goog.events.Event} event
 *        The add event.
 */
lfpug.ui.component.list.BaseList.prototype.addEventInternal =
    function(event) {
  var model = event.getData();
  var index = event.getItemIndex();
  var count = this.model_.getLength();
  var value = Math.min(count, index);
  this.addChildModelAt(model, value);
};


/**
 * @protected
 *
 * @param {goog.events.Event} event
 *        The remove event.
 */
lfpug.ui.component.list.BaseList.prototype.removeEventInternal =
    function(event) {
  var model = event.getData();
  this.removeChildModel(model);
};


/**
 * @protected
 * @param {goog.events.Event} event
 *        The change event.
 */
lfpug.ui.component.list.BaseList.prototype.changeEventInternal =
    function(event) {
  // we assume that the child binds to it's own change. so we do nothing.
};


/**
 * @protected
 * @param {goog.events.Event} event
 *        The move Event.
 */
lfpug.ui.component.list.BaseList.prototype.moveEventInternal =
    function(event) {
  var model = event.getData();
  var index = event.getItemIndex();
  this.addChildModelAt(model, index);
};
